﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;


public enum eMjSitIndex
{
    None = -1,
    //逆时针, 出牌也是逆时针方向的
    East,
    North,
    West,
    South,
}

//单个麻将玩家
public class MjSitPlayer : IComparer<MjCard>
{
    //public PlayerInfo m_PlayerInfo;
    private int m_SitIndex = 0; //位置
    public bool m_IsReady; //是否已准备
    private readonly List<MjCard> m_HandCards = new List<MjCard>(13); //手牌
    //private readonly MjCard[] m_HandCards = new MjCard[13]; //手牌
    private List<MjCardGroup> m_CardGroups = new List<MjCardGroup>(4); //副露
    public bool m_Ting; //是否已听牌
    private MjCard m_LastFaCard; //最后一次拿到的牌
    public readonly List<MjCard> m_ChuCards = new List<MjCard>(); //已出牌
    public bool m_HostState; //是否托管
    //public int m_Score; //积分
    private int[,] m_TypeNumCount = new int[5, 10];

    public MjSitPlayer(eMjSitIndex sitIndex)
    {
        m_SitIndex = (int)sitIndex;
    }

    public int SitIndex
    {
        get { return m_SitIndex; }
    }

    public MjCard GetHandCard(int index)
    {
        return m_HandCards[index];
    }

    public int GetHandCardCount()
    {
        return m_HandCards.Count;
    }

    public MjCardGroup GetCardGroup(int index)
    {
        return m_CardGroups[index];
    }

    public int GetCardGroupCount()
    {
        return m_CardGroups.Count;
    }

    //开局发牌
    public void StartFaPai(MjCard c)
    {
        m_HandCards.Add(c);
        if (c != MjCard.Empty)
        {
            m_TypeNumCount[c.Type, c.Num]++;
        }
    }

    //开局发牌结束, 理牌
    public void StartLiPai()
    {
        m_HandCards.Sort(this);
    }

    public int Compare(MjCard a, MjCard b)
    {
        return a.Id - b.Id; //asc; 返回: <0则a排b前面; >0则a排b后面; =0则排序不变;
    }

    //回合发牌
    public void RoundFaPai(MjCard c)
    {
        m_LastFaCard = c;
        if (c != MjCard.Empty)
        {
            m_TypeNumCount[c.Type, c.Num]++;
        }
    }

    public MjCard LastFaCard
    {
        get { return m_LastFaCard; }
    }

    public bool RoundChuPai(MjCard c)
    {
        //其他玩家: 手牌因为不可见, 所以都是存的占位牌(Empty)
        if (m_HandCards[0] == MjCard.Empty)
        {
            m_LastFaCard = null;
            m_ChuCards.Add(c);
            return true;
        }
        
        m_TypeNumCount[c.Type, c.Num]--;
        if (m_LastFaCard == c)
        {
            m_LastFaCard = null;
        }
        else
        {
            bool isFindCard = false;
            for (int i = m_HandCards.Count - 1; i >= 0; --i)
            {
                var c2 = m_HandCards[i];
                if (c2.Id == c.Id)
                {
                    m_HandCards.RemoveAt(i);
                    isFindCard = true;
                    break;
                }
            }
            if (!isFindCard)
                return false;
            
            if (null != m_LastFaCard)
            {
                int low = 0;
                int high = m_HandCards.Count - 1;
                while (low <= high)
                {
                    int mid = (low + high) >> 1;
                    if (m_LastFaCard.Id < m_HandCards[mid].Id)
                        high = mid - 1;
                    else
                        low = mid + 1;
                }
                m_HandCards.Insert(low, m_LastFaCard);
                m_LastFaCard = null;
            }
        }
        
        m_ChuCards.Add(c);
        return true;
    }

    //#################### 已出牌
    
    public int GetChuCount()
    {
        return m_ChuCards.Count;
    }

    public MjCard GetLastChuCard()
    {
        int lastIndex = m_ChuCards.Count - 1;
        return m_ChuCards[lastIndex];
    }

    //被别人吃碰杠时, 弹出一张牌到别人的附露
    public MjCard PopLastChuCard()
    {
        int lastIndex = m_ChuCards.Count - 1;
        var c = m_ChuCards[lastIndex];
        m_ChuCards.RemoveAt(lastIndex);
        return c;
    }
    
    //####################

    public void Peng(MjCard otherCard, eMjSitIndex otherSitIndex, out MjCard c1, out MjCard c2)
    {
        c1 = null;
        c2 = null;
        for (int i = 0; i < m_HandCards.Count; ++i)
        {
            var c = m_HandCards[i];
            if (c.Type == otherCard.Type && c.Num == otherCard.Num)
            {
                c1 = c;
                c2 = m_HandCards[i + 1];

                var group = new MjCardGroup();
                group.Set3CardAction(eMjAction.Peng, otherCard, otherSitIndex, c1, c2);
                m_CardGroups.Add(group);

                int j = i;
                i += 2;
                //牌往前移2张
                for (; i < m_HandCards.Count; ++i)
                    m_HandCards[j++] = m_HandCards[i];
                m_HandCards.RemoveAt(m_HandCards.Count - 1);
                m_HandCards.RemoveAt(m_HandCards.Count - 1);
                
                m_TypeNumCount[c.Type, c.Num] -= 2;
                break;
            }
        }
    }

    public void Chi(MjCard otherCard, eMjSitIndex otherSitIndex, out MjCard c1, out MjCard c2)
    {
        c1 = null;
        c2 = null;
        for (int i = 0; i < m_HandCards.Count; ++i)
        {
            var c = m_HandCards[i];
            if (c.Type == otherCard.Type && c.Num == otherCard.Num)
            {
                c1 = c;
                c2 = m_HandCards[i + 1];

                var group = new MjCardGroup();
                group.Set3CardAction(eMjAction.Peng, otherCard, otherSitIndex, c1, c2);
                m_CardGroups.Add(group);

                int j = i;
                i += 2;
                //牌往前移2张
                for (; i < m_HandCards.Count; ++i)
                    m_HandCards[j++] = m_HandCards[i];
                break;
            }
        }
    }

    public void PrintCards()
    {
        var sb = new StringBuilder();
        for (int i = 0; i < m_HandCards.Count; ++i)
        {
            var c = m_HandCards[i];
            sb.Append($"{c.Type}-{c.Num}({c.Id}),");
        }
        Debug.Log($"{sb.ToString()}");
        if (null != m_LastFaCard)
            Debug.Log($"{m_LastFaCard.Type}-{m_LastFaCard.Num}({m_LastFaCard.Id})");
    }


    public bool IsGang(MjCard c)
    {
        int num = m_TypeNumCount[c.Type, c.Num];
        return num >= 3;
    }

    public bool IsPeng(MjCard c)
    {
        int num = m_TypeNumCount[c.Type, c.Num];
        return num >= 2;
    }

    public bool IsChi(MjCard c)
    {
        int tmpType = c.Type;
        int tmpNum = c.Num;
        byte flag = 0;
        if (tmpNum >= 3)
        {
            int num1 = m_TypeNumCount[tmpType, tmpNum - 2];
            if (num1 > 0) flag |= 0x01;
        }
        if (tmpNum >= 2)
        {
            int num2 = m_TypeNumCount[tmpType, tmpNum - 1];
            if (num2 > 0) flag |= 0x02;
        }
        if (tmpNum <= 8)
        {
            int num3 = m_TypeNumCount[tmpType, tmpNum + 1];
            if (num3 > 0) flag |= 0x04;
        }
        if (tmpNum <= 7)
        {
            int num4 = m_TypeNumCount[tmpType, tmpNum + 2];
            if (num4 > 0) flag |= 0x08;
        }
        return 3 == flag || 6 == flag || 12 == flag;
    }

    public int[] GetHandCardIds()
    {
        int[] ids = new int[m_HandCards.Count];
        for (int i = 0; i < m_HandCards.Count; ++i)
        {
            var c = m_HandCards[i];
            ids[i] = c.Id;
        }
        return ids;
    }

    public bool IsHu(MjCard c)
    {
        return false;
    }

    private Stack<MjCard> m_Stack = new Stack<MjCard>();
    public bool IsTing(int count)
    {
        if (1 == count)
            return true;

        if (2 == count)
        {
            MjCard c1 = null, c2 = null;
            for (int i = 0; i < m_HandCards.Count; ++i)
            {
                var c = m_HandCards[i];
                if ("InStack" == c.UserFlag) continue;
                if (null == c1)
                {
                    c1 = c;
                }
                else if (null == c2)
                {
                    c2 = c;
                    break;
                }
            }
            if (c1.Type != c2.Type) //两张不同类型单牌
                return false;
            int numDelta = c2.Num - c1.Num;
            if (numDelta >= 0 && numDelta <= 2) //0_对子, 1_缺边牌, 2_缺中牌
                return true;
            return false;
        }

        if (3 == count)
        {
            //杠开, 两个对子不能胡
            MjCard lastCard = null;
            for (int i = 0; i < m_HandCards.Count; ++i)
            {
                var c = m_HandCards[i];
                if ("InStack" == c.UserFlag) continue;
                if (null == lastCard)
                    lastCard = c;
                else if (lastCard.Type != c.Type || lastCard.Num != c.Num)
                    return false;
            }

            return true;
        }

        if (4 == count)
        {
            //拿掉刻子是否听牌
            for (int i = 0; i < m_HandCards.Count - 2; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                var c3 = m_HandCards[i + 2];
                if ("InStack" == c3.UserFlag) continue;
                
                if (c1.Type == c2.Type  && c1.Num == c2.Num
                    && c2.Type == c3.Type && c2.Num == c3.Num)
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    c3.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    m_Stack.Push(c3);
                    bool result = IsTing(count - 3);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    
                    if (result)
                        return true;
                }
            }
            
            //拿掉对子是否听牌
            for (int i = 0; i < m_HandCards.Count - 1; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                
                if (c1.Type == c2.Type && c1.Num == c2.Num)
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    bool result = IsTing(count - 2);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    
                    if (result)
                        return true;
                }
            }
            
            //拿掉顺子是否听牌
            for (int i = 0; i < m_HandCards.Count - 2; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                var c3 = m_HandCards[i + 2];
                if ("InStack" == c3.UserFlag) continue;
                
                if (c1.Type == c2.Type  && c2.Type == c3.Type
                    && 1 == (c2.Num - c1.Num) && 1 == (c3.Num - c2.Num))
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    c3.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    m_Stack.Push(c3);
                    bool result = IsTing(count - 3);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    
                    if (result) 
                        return true;
                }
            }
        }
        
        if (Is13Yao()) 
            return true;
        
        //[5, 12]张牌
        //拿掉刻子是否听牌
        for (int i = 0; i < m_HandCards.Count - 2; ++i)
        {
            var c1 = m_HandCards[i];
            if ("InStack" == c1.UserFlag) continue;
            var c2 = m_HandCards[i + 1];
            if ("InStack" == c2.UserFlag) continue;
            var c3 = m_HandCards[i + 2];
            if ("InStack" == c3.UserFlag) continue;
            
            if (c1.Type == c2.Type  && c1.Num == c2.Num
                && c2.Type == c3.Type && c2.Num == c3.Num)
            {
                c1.UserFlag = "InStack";
                c2.UserFlag = "InStack";
                c3.UserFlag = "InStack";
                m_Stack.Push(c1);
                m_Stack.Push(c2);
                m_Stack.Push(c3);
                bool result = IsTing(count - 3);
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                
                if (result)
                    return true;
            }
        }
        
        //拿掉顺子是否听牌
        for (int i = 0; i < m_HandCards.Count - 2; ++i)
        {
            var c1 = m_HandCards[i];
            if ("InStack" == c1.UserFlag) continue;
            var c2 = m_HandCards[i + 1];
            if ("InStack" == c2.UserFlag) continue;
            var c3 = m_HandCards[i + 2];
            if ("InStack" == c3.UserFlag) continue;
            
            if (c1.Type == c2.Type  && c2.Type == c3.Type
                && 1 == (c2.Num - c1.Num) && 1 == (c3.Num - c2.Num))
            {
                c1.UserFlag = "InStack";
                c2.UserFlag = "InStack";
                c3.UserFlag = "InStack";
                m_Stack.Push(c1);
                m_Stack.Push(c2);
                m_Stack.Push(c3);
                bool result = IsTing(count - 3);
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                
                if (result) 
                    return true;
            }
        }

        return false;
    }

    public bool Is13Yao()
    {
        if (13 != m_HandCards.Count) return false;

        //1筒,9筒,1条,9条,1万,9万,东,南,西,北,中,发,白
        if (1 != m_TypeNumCount[MjCard.Tong_1_1.Type, MjCard.Tong_1_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Tong_9_1.Type, MjCard.Tong_9_1.Num]) return false;
        
        if (1 != m_TypeNumCount[MjCard.Tiao_1_1.Type, MjCard.Tiao_1_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Tiao_9_1.Type, MjCard.Tiao_9_1.Num]) return false;
        
        if (1 != m_TypeNumCount[MjCard.Wan_1_1.Type, MjCard.Wan_1_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Wan_9_1.Type, MjCard.Wan_9_1.Num]) return false;
        
        if (1 != m_TypeNumCount[MjCard.Dong_1.Type, MjCard.Dong_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Nan_1.Type, MjCard.Nan_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Xi_1.Type, MjCard.Xi_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Bei_1.Type, MjCard.Bei_1.Num]) return false;
        
        if (1 != m_TypeNumCount[MjCard.Zhong_1.Type, MjCard.Zhong_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Fa_1.Type, MjCard.Fa_1.Num]) return false;
        if (1 != m_TypeNumCount[MjCard.Bai_1.Type, MjCard.Bai_1.Num]) return false;
        
        return true;
    }
    
    public List<int> m_TingResult = new List<int>();
    public void TingResult(int count)
    {
        if (1 == count)
        {
            for (int i = 0; i < m_HandCards.Count; ++i)
            {
                var c = m_HandCards[i];
                if ("InStack" == c.UserFlag) continue;
                m_TingResult.Add(c.NumId);
            }
            return;
        }

        if (2 == count)
        {
            MjCard c1 = null, c2 = null;
            for (int i = 0; i < m_HandCards.Count; ++i)
            {
                var c = m_HandCards[i];
                if ("InStack" == c.UserFlag) continue;
                if (null == c1)
                {
                    c1 = c;
                }
                else if (null == c2)
                {
                    c2 = c;
                    break;
                }
            }
            if (c1.Type != c2.Type) //两张不同类型单牌
                return;
            int numDelta = c2.Num - c1.Num;
            if (0 == numDelta) //0_对子
            {
                m_TingResult.Add(c1.NumId);
            }
            else if (1 == numDelta) //1_缺边牌
            {
                if (c1.Num > 1)
                    m_TingResult.Add(c1.NumId - 1);
                if (c2.Num < 9)
                    m_TingResult.Add(c2.NumId + 1);
            }
            else if (2 == numDelta) //2_缺中牌
            {
                m_TingResult.Add(c1.NumId + 1);
            }
            return;
        }

        if (3 == count)
        {
            //杠开, 两个对子不能胡
            MjCard lastCard = null;
            for (int i = 0; i < m_HandCards.Count; ++i)
            {
                var c = m_HandCards[i];
                if ("InStack" == c.UserFlag) continue;
                if (null == lastCard)
                    lastCard = c;
                else if (lastCard.Type != c.Type || lastCard.Num != c.Num)
                    return;
            }
            m_TingResult.Add(lastCard.NumId);
            return;
        }

        if (4 == count)
        {
            //拿掉刻子是否听牌
            for (int i = 0; i < m_HandCards.Count - 2; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                var c3 = m_HandCards[i + 2];
                if ("InStack" == c3.UserFlag) continue;
                
                if (c1.Type == c2.Type  && c1.Num == c2.Num
                    && c2.Type == c3.Type && c2.Num == c3.Num)
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    c3.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    m_Stack.Push(c3);
                    TingResult(count - 3);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                }
            }
            
            //拿掉对子是否听牌
            for (int i = 0; i < m_HandCards.Count - 1; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                
                if (c1.Type == c2.Type && c1.Num == c2.Num)
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    TingResult(count - 2);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                }
            }
            
            //拿掉顺子是否听牌
            for (int i = 0; i < m_HandCards.Count - 2; ++i)
            {
                var c1 = m_HandCards[i];
                if ("InStack" == c1.UserFlag) continue;
                var c2 = m_HandCards[i + 1];
                if ("InStack" == c2.UserFlag) continue;
                var c3 = m_HandCards[i + 2];
                if ("InStack" == c3.UserFlag) continue;
                
                if (c1.Type == c2.Type  && c2.Type == c3.Type
                    && 1 == (c2.Num - c1.Num) && 1 == (c3.Num - c2.Num))
                {
                    c1.UserFlag = "InStack";
                    c2.UserFlag = "InStack";
                    c3.UserFlag = "InStack";
                    m_Stack.Push(c1);
                    m_Stack.Push(c2);
                    m_Stack.Push(c3);
                    TingResult(count - 3);
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                    m_Stack.Pop().UserFlag = "";
                }
            }
        }

        if (Is13Yao())
        {
            m_TingResult.Add(MjCard.Tong_1_1.NumId);
            m_TingResult.Add(MjCard.Tong_9_1.NumId);
            m_TingResult.Add(MjCard.Tiao_1_1.NumId);
            m_TingResult.Add(MjCard.Tiao_9_1.NumId);
            m_TingResult.Add(MjCard.Wan_1_1.NumId);
            m_TingResult.Add(MjCard.Wan_9_1.NumId);
            m_TingResult.Add(MjCard.Dong_1.NumId);
            m_TingResult.Add(MjCard.Nan_1.NumId);
            m_TingResult.Add(MjCard.Xi_1.NumId);
            m_TingResult.Add(MjCard.Bei_1.NumId);
            m_TingResult.Add(MjCard.Zhong_1.NumId);
            m_TingResult.Add(MjCard.Fa_1.NumId);
            m_TingResult.Add(MjCard.Bai_1.NumId);
            return;
        }

        //[5, 12]张牌
        //拿掉刻子是否听牌
        for (int i = 0; i < m_HandCards.Count - 2; ++i)
        {
            var c1 = m_HandCards[i];
            if ("InStack" == c1.UserFlag) continue;
            var c2 = m_HandCards[i + 1];
            if ("InStack" == c2.UserFlag) continue;
            var c3 = m_HandCards[i + 2];
            if ("InStack" == c3.UserFlag) continue;
            
            if (c1.Type == c2.Type  && c1.Num == c2.Num
                && c2.Type == c3.Type && c2.Num == c3.Num)
            {
                c1.UserFlag = "InStack";
                c2.UserFlag = "InStack";
                c3.UserFlag = "InStack";
                m_Stack.Push(c1);
                m_Stack.Push(c2);
                m_Stack.Push(c3);
                TingResult(count - 3);
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
            }
        }
        
        //拿掉顺子是否听牌
        for (int i = 0; i < m_HandCards.Count - 2; ++i)
        {
            var c1 = m_HandCards[i];
            if ("InStack" == c1.UserFlag) continue;
            var c2 = m_HandCards[i + 1];
            if ("InStack" == c2.UserFlag) continue;
            var c3 = m_HandCards[i + 2];
            if ("InStack" == c3.UserFlag) continue;
            
            if (c1.Type == c2.Type  && c2.Type == c3.Type
                && 1 == (c2.Num - c1.Num) && 1 == (c3.Num - c2.Num))
            {
                c1.UserFlag = "InStack";
                c2.UserFlag = "InStack";
                c3.UserFlag = "InStack";
                m_Stack.Push(c1);
                m_Stack.Push(c2);
                m_Stack.Push(c3);
                TingResult(count - 3);
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
                m_Stack.Pop().UserFlag = "";
            }
        }
    }

    public void PrintTingResult()
    {
        PrintCollection(m_TingResult);
    }

    public void Reset()
    {
        m_HandCards.Clear();
        Array.Clear(m_TypeNumCount, 0, m_TypeNumCount.Length);
    }

    public void PrintCollection<T>(ICollection<T> list)
    {
        var sb = new StringBuilder();
        foreach (var item in list)
        {
            sb.Append($"{item.ToString()},");
        }
        Debug.Log(sb.ToString());
    }
}

